using System;
using System.Collections.Generic;
using NUnit.Framework;

namespace parts.tests
{
    [TestFixture]
    public class Flow_without_implementation
    {
        [SetUp]
        public void Setup() {
            Part.Cleanup();
        }

        [Test]
        public void Without_implementation() {
            ToDictionary("a=1");
        }

        [Test]
        public void With_method_implementation() {
            Part.Add<string, IEnumerable<string>>("split_into_pairs", ToDictionaryMethods.SplitIntoPairs);
            Part.Add<IEnumerable<string>, IEnumerable<KeyValuePair<string, string>>>("split_into_key_value_pairs", ToDictionaryMethods.SplitIntoKeyValuePairs);
            Part.Add<IEnumerable<KeyValuePair<string, string>>, IDictionary<string, string>>("build_dictionary", ToDictionaryMethods.BuildDictionary);

            var dictionary = ToDictionary("a=1");
            Assert.That(dictionary.Count, Is.EqualTo(1));
            Assert.That(dictionary["a"], Is.EqualTo("1"));
        }

        [Test]
        public void With_class_implementation() {
            Part.Add("split_into_pairs",  new SplitIntoPairs());
            Part.Add("split_into_key_value_pairs", new SplitIntoKeyValuePairs());
            Part.Add("build_dictionary", new BuildDictionary());

            var dictionary = ToDictionary("a=1");
            Assert.That(dictionary.Count, Is.EqualTo(1));
            Assert.That(dictionary["a"], Is.EqualTo("1"));
        }

        public IDictionary<string,string > ToDictionary(string configuration) {
            var split_into_pairs = new Part<string, IEnumerable<string>>("split_into_pairs");
            var split_into_key_value_pairs = new Part<IEnumerable<string>, IEnumerable<KeyValuePair<string, string>>>("split_into_key_value_pairs");
            var build_dictionary = new Part<IEnumerable<KeyValuePair<string, string>>, IDictionary<string, string>>("build_dictionary");

            IDictionary<string, string> result = new Dictionary<string, string>();

            split_into_pairs.Result += split_into_key_value_pairs.Process;
            split_into_key_value_pairs.Result += build_dictionary.Process;
            build_dictionary.Result += x => result = x;

            split_into_pairs.Process(configuration);
            return result;
        }
    }

    public class BuildDictionary : IPart<IEnumerable<KeyValuePair<string, string>>, IDictionary<string, string>>
    {
        public void Process(IEnumerable<KeyValuePair<string, string>> keyValuePairs) {
            var result = new Dictionary<string, string>();
            foreach (var keyValuePair in keyValuePairs) {
                result.Add(keyValuePair.Key, keyValuePair.Value);
            }
            Result(result);
        }

        public event Action<IDictionary<string, string>> Result;
    }

    public class SplitIntoKeyValuePairs : IPart<IEnumerable<string>, IEnumerable<KeyValuePair<string, string>>>
    {
        public void Process(IEnumerable<string> pairs) {
            var result = new List<KeyValuePair<string, string>>();
            foreach (var pair in pairs) {
                var kv = pair.Split('=');
                result.Add(new KeyValuePair<string, string>(kv[0], kv[1]));
            }
            Result(result);
        }

        public event Action<IEnumerable<KeyValuePair<string, string>>> Result;
    }

    public class ToDictionaryMethods
    {
        public static IEnumerable<string> SplitIntoPairs(string configuration) {
            return configuration.Split(';');
        }

        public static IEnumerable<KeyValuePair<string, string>> SplitIntoKeyValuePairs(IEnumerable<string> pairs) {
            foreach (var pair in pairs) {
                var kv = pair.Split('=');
                yield return new KeyValuePair<string, string>(kv[0], kv[1]);
            }
        }

        public static IDictionary<string, string> BuildDictionary(IEnumerable<KeyValuePair<string, string>> keyValuePairs) {
            var result = new Dictionary<string, string>();
            foreach (var keyValuePair in keyValuePairs) {
                result.Add(keyValuePair.Key, keyValuePair.Value);
            }
            return result;
        }
    }

    public class SplitIntoPairs : IPart<string, IEnumerable<string>>
    {
        public void Process(string configuration) {
            Result(configuration.Split(';'));
        }

        public event Action<IEnumerable<string>> Result;
    }
}